package org.bjtu.word2vec;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import cn.edu.bjtu.abstractimpl.analyzer.AnsjDocumentAnalyzer;
import cn.edu.bjtu.classimpl.parser.HiveWechatParser;
import cn.edu.bjtu.classimpl.parser.LineParser;
import cn.edu.bjtu.interfaces.ModelStatus;
import cn.edu.bjtu.interfaces.document.IDocument;
import cn.edu.bjtu.interfaces.parser.Parser;
import cn.edu.bjtu.interfaces.segment.DocumentSegmentation;
import cn.edu.bjtu.interfaces.vector.IDocumentVector;
import cn.edu.bjtu.model.dl4jword2vec.DL4jWordVecModel;
import cn.edu.bjtu.model.word2vec.Word2VecForTransformingDocs;
import cn.edu.bjtu.tools.FileInfo;
import cn.edu.bjtu.tools.FileUtil;
import cn.edu.bjtu.tools.ModelInfo;
import cn.edu.bjtu.tools.ThreadLocalDateUtil;
import cn.edu.bjtu.tools.message.DocumentVectorMessage;
import cn.edu.bjtu.tools.message.FileInfoMessage;
import cn.edu.bjtu.tools.message.ModelInfoMessage;
import net.sf.json.JSONObject;

@RestController
@RequestMapping({ "/" })
public class DL4jModelControl extends BaseController {
	private static final Log LOG = LogFactory.getLog(DL4jModelControl.class);
	private DL4jWordVecModel dl4jWordVecModel = DL4jWordVecModel.getInstance();

	// 获取训练数据信息（Word2Vec）
	@RequestMapping(value = { "query/dataset" }, method = { RequestMethod.GET })
	public String getTrainFile() {
		List<FileInfo> fileInfo = dl4jWordVecModel.getFileInfo();
		if (fileInfo != null) {
			return dumpJSON(getReturnMessage(200, "", FileInfoMessage.class));
		} else {
			return dumpJSON(getReturnMessage(200, "the train file isn't exist!", FileInfoMessage.class));
		}
	}

	// 建模（Word2Vec）
	@RequestMapping(value = ("get/build"))
	public String word2VecmModeling() {
		String result = "";
		ModelInfoMessage modelInfoMessage = null;
		ModelStatus modelStatus = dl4jWordVecModel.builderModel(null);
		String dl4jModelFile = dl4jWordVecModel.getDL4JMODEL();
		if (modelStatus.getstatus() == 1) {
			modelInfoMessage = getReturnMessage(200,"",ModelInfoMessage.class);//ModelInfoMessage(200, "");
			// 返回建模时间
			ModelInfo modelInfo = new ModelInfo(modelStatus.getBuildTime(),
					dl4jModelFile.substring(dl4jModelFile.lastIndexOf(File.separator)));
			modelInfoMessage.setModelInfo(modelInfo);
			return dumpJSON(modelInfo);
		} else if (modelStatus.getstatus() == -1) {
			return dumpJSON(getReturnMessage(3, "leaning train file is fail ", ModelInfoMessage.class));
		} else {
			return dumpJSON(getReturnMessage(404, "training file isn't exist", ModelInfoMessage.class));
		}
	}

	// 文本格式（直接以文本形式用http传输）
	@RequestMapping(value = { "post/trans" }, method = { RequestMethod.POST, RequestMethod.GET })
	public String strToVec(@RequestParam(value = "text", required = true) String text) {
		String result = "";
		if (dl4jWordVecModel.isModelExist()) {
		//	dl4jWordVecModel.loadModelFromFile();
			DocumentVectorMessage documentVectorMessage = null;
			if (text.trim().length() == 0) {
				documentVectorMessage = new DocumentVectorMessage(404, "The doc is null");
				result = JSONObject.fromObject(documentVectorMessage).toString();
			} else {
				documentVectorMessage = new DocumentVectorMessage(200, "success");
				List<IDocumentVector> documentVectors = dl4jWordVecModel.transformDoc(text);
				documentVectorMessage.setData(documentVectors);
				result = JSONObject.fromObject(documentVectorMessage).toString();
			}
		} else {
			ModelInfoMessage modelInfoMessage = null;
			modelInfoMessage = new ModelInfoMessage(404, "model isn't exist");
			result = JSONObject.fromObject(modelInfoMessage).toString();
		}
		return result;
	}

	// 单文件（单文件单文档、单文件多文档）
	@RequestMapping(value = { "post/transfile" }, method = RequestMethod.POST)
	public String docToVec(HttpServletRequest req, HttpServletResponse res) throws Exception {
		String result = "";
		DocumentVectorMessage documentVectorMessage = null;
		ModelInfoMessage modelInfoMessage = null;
		if (dl4jWordVecModel.isModelExist()) {
			//dl4jWordVecModel.loadModelFromFile();
			//将上传的文件写入临时文件
			String transformDoc = ApplicationConfig.getInstance().getProperty("transform_dir")
					+ ThreadLocalDateUtil.getDateFormat().format(new Date()) + ".txt";
			// 流处理方式，防止因未关闭流引起的问题
			try (BufferedWriter writer = new BufferedWriter(
					new OutputStreamWriter(new FileOutputStream(transformDoc)))) {
				// 创建一个通用的多部分解析器
				CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
						req.getSession().getServletContext());
				// 判断 request 是否有文件上传,即多部分请求
				if (multipartResolver.isMultipart(req)) {
					// 转换成多部分request
					MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) req;
					// 取得request中的所有文件名
					Iterator<String> iter = multiRequest.getFileNames();
					while (iter.hasNext()) {
						// 取得上传文件
						MultipartFile file = multiRequest.getFile(iter.next());
						if (file != null) {
							BufferedReader br = new BufferedReader(
									new InputStreamReader(file.getInputStream(), "utf-8"));
							String line = "";
							while ((line = br.readLine()) != null) {
								writer.write(line);
								writer.newLine();
							}
						}
					}
				}
			}
			File filetransform = new File(transformDoc);
			try {
				List<IDocumentVector> documentVectors = dl4jWordVecModel
						.transform(dl4jWordVecModel.getDoucument(transformDoc));
				if (documentVectors != null) {
					documentVectorMessage = new DocumentVectorMessage(200, "success");
					documentVectorMessage.setData(documentVectors);
					result = JSONObject.fromObject(documentVectorMessage).toString();
				} else {
					modelInfoMessage = new ModelInfoMessage(404, "transform file isn't exist");
					result = JSONObject.fromObject(modelInfoMessage).toString();
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				// 临时文件转换之后删除该临时文件
				if (filetransform.exists()) {
					filetransform.delete();
				}
			}
		} else {
			modelInfoMessage = new ModelInfoMessage(404, "model isn't exist");
			result = JSONObject.fromObject(modelInfoMessage).toString();
		}
		return result;
	}

	// 多文件转换（多文件单文档、多文件多文档）
	@RequestMapping(value = { "post/transfiles" }, method = RequestMethod.POST)
	public void docsToVecs(HttpServletRequest req, HttpServletResponse res) throws IOException {
		ModelInfoMessage modelInfoMessage = null;
		if (dl4jWordVecModel.isModelExist()) {
			//dl4jWordVecModel.loadModelFromFile();
			List<IDocumentVector> iter = null;
			File filelist = null;
			// 创建一个通用的多部分解析器
			CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
					req.getSession().getServletContext());
			// 判断 request 是否有文件上传,即多部分请求
			if (multipartResolver.isMultipart(req)) {
				//将上传的多文件记录写入一个临时文件用于转换
				filelist = new File(ApplicationConfig.getInstance().getProperty("transform_dir")
						+ ThreadLocalDateUtil.getDateFormat().format(new Date()) + ".txt");
				if (!filelist.exists()) {
					filelist.createNewFile();
				}
				try (BufferedWriter writer = new BufferedWriter(
						new OutputStreamWriter(new FileOutputStream(filelist), "utf-8"))) {
					// 转换成多部分request
					MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) req;
					// 取得request中的所有文件名
					Iterator<String> iter1 = multiRequest.getFileNames();
					while (iter1.hasNext()) {
						// 取得上传文件
						MultipartFile file = multiRequest.getFile(iter1.next());
						if (file != null) {
							BufferedReader br = new BufferedReader(
									new InputStreamReader(file.getInputStream(), "utf-8"));
							String line = "";
							while ((line = br.readLine()) != null) {
								writer.write(line);
								writer.newLine();
							}
						}
					}
				}

			}
			if (filelist.exists() && filelist.isDirectory()) {
				iter = dl4jWordVecModel.transform(dl4jWordVecModel.getDocuments(filelist.getAbsolutePath()));
			} else if (filelist.exists() && filelist.isFile()) {
				iter = dl4jWordVecModel.transform(dl4jWordVecModel.getDoucument(filelist.getAbsolutePath()));
			}
			// 写入文件
			String filePath = ApplicationConfig.getInstance().getProperty("transform_dir")
					+ ThreadLocalDateUtil.getDateFormat().format(new Date() + ".txt");
			dl4jWordVecModel.writeToFile(iter, filePath);
			// 数据返回(文件流形式)
			try (FileInputStream hFile = new FileInputStream(filePath)) {
				int length = hFile.available();
				byte[] data = new byte[length];
				hFile.read(data);
				FileUtil.OutPutStream(new String(data), res);
				if (filelist.exists()) {
					filelist.delete();
				}
			}
		} else {
			modelInfoMessage = new ModelInfoMessage(404, "model isn't exist");
			JSONObject.fromObject(modelInfoMessage).toString();
		}
	}

	// 单文件（单文件单文档、单文件多文档文件较大时）
	@RequestMapping(value = { "post/transbigfile" }, method = RequestMethod.POST)
	public  void bigDocToVec(HttpServletRequest req, HttpServletResponse res) throws Exception {
		String result ;
		if (dl4jWordVecModel.isModelExist()) {
			//将上传的文档存储到本地文件
			String tranformFile = ApplicationConfig.getInstance().getProperty("transform_dir")
					+ ThreadLocalDateUtil.getDateFormat().format(new Date()) + ".txt";
			// 流处理方式，防止因未关闭流引起的问题
			try (BufferedWriter writer = new BufferedWriter(
					new OutputStreamWriter(new FileOutputStream(tranformFile), "utf-8"))) {
				// 创建一个通用的多部分解析器
				CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
						req.getSession().getServletContext());
				// 判断 request 是否有文件上传,即多部分请求
				if (multipartResolver.isMultipart(req)) {
					// 转换成多部分request
					MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) req;
					// 取得request中的所有文件名
					Iterator<String> iter = multiRequest.getFileNames();
					while (iter.hasNext()) {
						// 取得上传文件
						MultipartFile file = multiRequest.getFile(iter.next());
						if (file != null) {
							BufferedReader br = new BufferedReader(
									new InputStreamReader(file.getInputStream(), "utf-8"));
							String line = "";
							while ((line = br.readLine()) != null) {
								writer.write(line);
								writer.newLine();
							}
						}
					}

				}
			}
			File file = new File(tranformFile);
			if (file.exists()) {
				dl4jWordVecModel.dealBigFileTranform(tranformFile, res);
			} else {
				FileInfoMessage fileInfoMessage = new FileInfoMessage(1, "file isn't exist!");
				result = JSONObject.fromObject(fileInfoMessage).toString();
				FileUtil.OutPutStream(result, res);
			}
		} else {
			ModelInfoMessage modelInfoMessage = null;
			modelInfoMessage = new ModelInfoMessage(404, "model isn't exist");
			result = JSONObject.fromObject(modelInfoMessage).toString();
			FileUtil.OutPutStream(result, res);
		}
	}


	/**
	 * 判断模型是否存在
	 * 
	 * @return
	 * @throws IOException
	 */
	@RequestMapping(value = { "query/exist" })
	public String judgeModelExist() throws IOException {
		String result = "";
		ModelInfoMessage modelInfoMessage;
		if (!dl4jWordVecModel.isModelExist()) {
			modelInfoMessage = new ModelInfoMessage(404, "");
			ModelInfo modelInfo = new ModelInfo("no_exist");
			modelInfoMessage.setModelInfo(modelInfo);
			result = JSONObject.fromObject(modelInfoMessage).toString();
		} else{
			ModelStatus modelStatus = dl4jWordVecModel.getLoadModelStatus();
			if(modelStatus !=null){
			if(modelStatus.getstatus() ==1 ||modelStatus.getstatus() ==-1){
				modelInfoMessage = new ModelInfoMessage(200, "");
				ModelInfo modelInfo = new ModelInfo("file_mem");
				modelInfoMessage.setModelInfo(modelInfo);
				result = JSONObject.fromObject(modelInfoMessage).toString();
			}
			}else{
				modelInfoMessage = new ModelInfoMessage(200, "");
				ModelInfo modelInfo = new ModelInfo("file_only");
				modelInfoMessage.setModelInfo(modelInfo);
				result = JSONObject.fromObject(modelInfoMessage).toString();
			}
		}
		return result;
	}
/**
 * 加载模型
 */
	@RequestMapping(value = { "query/load" })
	public String loadModel() throws IOException {
		String result = "";
		ModelInfoMessage modelInfoMessage;
		if (!dl4jWordVecModel.isModelExist()) {
			modelInfoMessage = new ModelInfoMessage(404, "");
			ModelInfo modelInfo = new ModelInfo("no_exist");
			modelInfoMessage.setModelInfo(modelInfo);
			result = JSONObject.fromObject(modelInfoMessage).toString();
		} else {
			ModelStatus modelStatus = dl4jWordVecModel.loadModelFromFile(null);
			if(modelStatus.getstatus() ==1 ||modelStatus.getstatus() ==-1){
				modelInfoMessage = new ModelInfoMessage(200, "");
				ModelInfo modelInfo = new ModelInfo("file_mem");
				modelInfoMessage.setModelInfo(modelInfo);
				result = JSONObject.fromObject(modelInfoMessage).toString();
			}else if(modelStatus.getstatus() ==-2) {
				modelInfoMessage = new ModelInfoMessage(400, "");
				ModelInfo modelInfo = new ModelInfo("file_only");
				modelInfoMessage.setModelInfo(modelInfo);
				result = JSONObject.fromObject(modelInfoMessage).toString();
			}
		}
		return result;
	}
}
